﻿#include <time.h>
#include <iostream>

#include "Eigen/Dense"
#include "Eigen/Sparse"
#include "Iteration.h"
#include "basis.h"
#include "Multigrid.h"
#include "cmdline.h"
#include "json.hpp"
#include "DimensionSelect.h"

using namespace Eigen;
using namespace std;

#define FIND_INDEX_RAW(str, c) ((long long)str.find_last_of(c))
#define FIND_INDEX(str, c) ((FIND_INDEX_RAW(str, c) == std::string::npos) ? -1 : FIND_INDEX_RAW(str, c))
int main(int argc, char **argv)
{
    std::string path(argv[0]);
    auto dir = path.substr(0, max(FIND_INDEX(path, '/'), FIND_INDEX(path, '\\')));
    std::string defaultPath = "../assets/input.json";

    cmdline::parser parser;

    parser.add("config", 'c', "Path of configuration file for specifying multigrid interpolation parameters.", false, dir + "/" + defaultPath);
    parser.add("output", 'o', "Path of diretory for saving output files.", false, string(""));
    parser.parse_check(argc, argv);

    options opt = options::LoadFromFile(parser.get<string>("config"));
    Function f(GET_DEFAULT_FUN(F)(opt.dim), GET_DEFAULT_FUN(DF)(opt.dim), GET_DEFAULT_FUN(LAPLACE)(opt.dim));
    Multigrid multigrid(opt.degree - 1, f, opt.dim);
    multigrid.setCycleType(opt.cycleChoice);
    multigrid.setBoundtype(opt.boundType);
    multigrid.setInterpolationType(opt.itype);
    multigrid.setRestrictionType(opt.rtype);
    runningLog log;
    clock_t startTime = clock();
    auto res = multigrid.Possion_BVP_Multigrid(opt.nu1, opt.nu2, opt.maxIteration, 1e-8, 2.0 / 3, &log);
    clock_t endTime = clock();
    double ms = (double)(endTime - startTime) * 1000. / CLOCKS_PER_SEC;
    auto outpath = parser.get<string>("output");
    std::cout << "The run time is:" << ms << "ms" << std::endl;
    if (outpath.length())
    {
        auto &multigridOut = std::get<0>(res);
        auto &analysis = std::get<1>(res);
        auto lastChar = outpath[outpath.length() - 1];
        if (lastChar != '/' && lastChar != '\\')
            outpath += '/';

        std::ofstream file(outpath + "multigrid.txt");
        if (!file.is_open())
            return 1;
        file << multigridOut;
        file.flush();
        file.close();

        file.open(outpath + "analysis.txt");
        if (!file.is_open())
            return 1;
        file << analysis;
        file.flush();
        file.close();

        nlohmann::json data = opt.serialize();
        data["error"] = log.err;
        data["count"] = log.count;
        data["runnig_time"] = ms;

        file.open(outpath + "log.txt");
        if (!file.is_open())
            return 1;
        file << data;
        file.flush();
        file.close();
    }

    return 0;
}